package cn.kgc.listener.canal;

import cn.hutool.core.collection.CollUtil;
import cn.kgc.base.BaseInfoProperties;
import cn.kgc.base.SystemConstant;
import cn.kgc.entity.Industry;
import cn.kgc.service.IndustryService;
import com.alibaba.otter.canal.protocol.CanalEntry;
import com.xpand.starter.canal.annotation.CanalEventListener;
import com.xpand.starter.canal.annotation.ListenPoint;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author YC
 * 监听industry表的数据变化,更新redis缓存中的数据
 * 注解@CanalEventListener用于标识一个类为Canal的事件监听器
 */
@Component
@Slf4j
@CanalEventListener
public class IndustryCanalListener extends BaseInfoProperties {

    @Resource
    private IndustryService industryService;

    /**
     * 监听表的删除数据操作
     * 注解@ListenPoint用于精确指定 监听的数据变更事件规则
     *
     * @param rowData 监听到的数据变化
     */
    @ListenPoint(
            destination = "hire",
            table = "industry",
            eventType = {
                    CanalEntry.EventType.DELETE
            }
    )
    public void listenerDelete(CanalEntry.RowData rowData) {
        // 删除之前的数据
        List<CanalEntry.Column> beforeColumnsList = rowData.getBeforeColumnsList();
        resetIndustryCache(beforeColumnsList);
    }

    /**
     * 监听表的新增修改数据操作
     * 注解@ListenPoint用于精确指定 监听的数据变更事件规则
     *
     * @param rowData 监听到的数据变化
     */
    @ListenPoint(
            destination = "hire",
            table = "industry",
            eventType = {
                    CanalEntry.EventType.INSERT,
                    CanalEntry.EventType.UPDATE
            }
    )
    public void listenInsertOrUpdate(CanalEntry.RowData rowData) {
        // 获取新增或修改后的所有字段
        List<CanalEntry.Column> afterColumns = rowData.getAfterColumnsList();
        resetIndustryCache(afterColumns);
    }

    /**
     * 重置行业缓存
     * Redis缓存设计：
     * [ 一级行业 , [ 二级行业1 , [ 三级行业1 , 三级行业2 , ... ] ] ,[ 二级行业2 , [ 三级行业 , ... ] ] , ... ]
     *
     * @param columnList 变更数据的一行字段与值
     */
    private void resetIndustryCache(List<CanalEntry.Column> columnList) {
        // 从变更数据的一行数据中获取某些字段与字段值
        String level = "";
        String fatherId = "";
        for (CanalEntry.Column column : columnList) {
            String columnName = column.getName();
            if ("level".equals(columnName)) {
                level = column.getValue();
            }
            if ("father_id".equals(columnName)) {
                fatherId = column.getValue();
            }
        }
        // 重置行业逻辑
        if ("1".equals(level)) {
            // 新增修改删除一级行业缓存，重置一级行业缓存
            List<Industry> topIndustry = industryService.getTopIndustry();
            redisUtil.set(SystemConstant.INDUSTRY_TOP_PREFIX, topIndustry);
        } else if ("3".equals(level)) {
            // 新增修改删除三级行业缓存
            List<Industry> thirdIndustry = industryService.getTopIndustry();
            String topId = industryService.getById(fatherId).getFatherId();
            List<Industry> topIndustry = industryService.getThirdIndustry(topId);
            if (CollUtil.isEmpty(topIndustry)) {
                // 如果当前一级行业下没有三级行业，保存一个空集合并设置过期时间（不直接删除缓存，防止缓存穿透）
                redisUtil.set(SystemConstant.INDUSTRY_THIRD_PREFIX + topId, thirdIndustry, 5, TimeUnit.SECONDS);
            } else {
                // 如果当前一级行业下有三级行业，重置三级行业对应的一级行业下所有的三级行业缓存
                redisUtil.set(SystemConstant.INDUSTRY_THIRD_PREFIX + topId, thirdIndustry);
            }
        }
    }

}
